#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-only
# Reason-GPL: import-scapy
import sys

from scapy.all import Ether, IP, UDP, TCP, Packet, bind_layers, get_if_list, sniff
from scapy.fields import *


def get_if():
    ifs=get_if_list()
    iface=None
    for i in get_if_list():
        if "eth0" in i:
            iface=i
            break;
    if not iface:
        print("Cannot find eth0 interface")
        exit(1)
    return iface

class SourceRoute(Packet):
   fields_desc = [ BitField("bos", 0, 1),
                   BitField("port", 0, 15)]

class SourceRoutingTail(Packet):
   fields_desc = [ XShortField("etherType", 0x800)]

bind_layers(Ether, SourceRoute, type=0x1234)
bind_layers(SourceRoute, SourceRoute, bos=0)
bind_layers(SourceRoute, SourceRoutingTail, bos=1)

def handle_pkt(pkt):
    print("\n" + "="*50)
    print("收到数据包!")

    if pkt.haslayer(IP):
        ip_layer = pkt[IP]
        print(f"IPv4数据包: {ip_layer.src} -> {ip_layer.dst}")

        if pkt.haslayer(TCP):
            print(f"TCP: 源端口 {pkt[TCP].sport} -> 目标端口 {pkt[TCP].dport}")
        elif pkt.haslayer(UDP):
            print(f"UDP: 源端口 {pkt[UDP].sport} -> 目标端口 {pkt[UDP].dport}")

        if pkt.haslayer(TCP) and pkt[TCP].payload:
            print(f"数据: {bytes(pkt[TCP].payload).decode('utf-8', errors='ignore')}")
        elif pkt.haslayer(UDP) and pkt[UDP].payload:
            print(f"数据: {bytes(pkt[UDP].payload).decode('utf-8', errors='ignore')}")

    elif pkt.haslayer(SourceRoute):
        print("源路由数据包")
        # 提取所有源路由头
        route_headers = []
        current = pkt
        while current.haslayer(SourceRoute):
            sr = current[SourceRoute]
            route_headers.append(f"端口:{sr.port}(BOS:{sr.bos})")
            current = current.payload

        print(f"路由路径: {' -> '.join(route_headers)}")

    print("数据包详情:")
    pkt.show2()
    print("="*50)
    sys.stdout.flush()

def main():
    iface = 'eth0'
    print(f"在接口 {iface} 上监听数据包...")
    print("监听UDP端口4321和TCP端口1234")
    sys.stdout.flush()

    # 监听两种类型的数据包
    sniff(filter="udp port 4321 or tcp port 1234", iface=iface,
          prn=lambda x: handle_pkt(x))

if __name__ == '__main__':
    main()
